﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using BitMiracle.LibTiff.Classic;
using System.IO;


namespace SplitMatch
{
    class HandleTIF
    {
        // 读取Tif，返回byte矩阵
        public static byte[,] ReadTifFile(string fileName)
        {
            Tiff input = Tiff.Open(fileName, "r");


            FieldValue[] value = input.GetField(TiffTag.IMAGEWIDTH);
            int width = value[0].ToInt();

            value = input.GetField(TiffTag.IMAGELENGTH);
            int height = value[0].ToInt();

            byte[,] bCsharp = new byte[height, width];

            for (int i = 0; i < height; ++i)
            {
                byte[] buf = new byte[width];
                input.ReadScanline(buf, i);

                for (int j = 0; j < width; j++) 
                {
                    bCsharp[i, j] = buf[j];
                }


                Console.WriteLine();
            }
            input.Close();

            return bCsharp;
        }

        // 输入一个byte矩阵，输出一个tif图片文件.
        public static void SaveTIFFile(byte[,] bSmall, string strSaveFile)
        {
            Tiff output = Tiff.Open(strSaveFile, "w");

            int height = bSmall.GetLength(0);
            int width = bSmall.GetLength(1);

            output.SetField(TiffTag.IMAGEWIDTH, width);
            output.SetField(TiffTag.IMAGELENGTH, height);
            output.SetField(TiffTag.SAMPLESPERPIXEL, 1);
            output.SetField(TiffTag.BITSPERSAMPLE, 8);
            output.SetField(TiffTag.ORIENTATION, BitMiracle.LibTiff.Classic.Orientation.TOPLEFT);
            output.SetField(TiffTag.ROWSPERSTRIP, height);
            output.SetField(TiffTag.XRESOLUTION, 100.0);
            output.SetField(TiffTag.YRESOLUTION, 100.0);
            output.SetField(TiffTag.RESOLUTIONUNIT, ResUnit.INCH);
            output.SetField(TiffTag.PLANARCONFIG, PlanarConfig.CONTIG);
            output.SetField(TiffTag.PHOTOMETRIC, Photometric.MINISBLACK);
            output.SetField(TiffTag.COMPRESSION, Compression.NONE);
            output.SetField(TiffTag.FILLORDER, FillOrder.MSB2LSB);

            for (int i = 0; i < height; ++i)
            {
                byte[] buf = new byte[width];
                for (int j = 0; j < width; ++j)
                {
                    // buf[j] = (byte)random.Next(255);

                    buf[j] = bSmall[i, j];
                }


                output.WriteScanline(buf, i);
            }
            output.Close();

        }

        // 输入文件名 返回Size
        public static mySize GetSize(string fileName)
        {
            

            Tiff input = Tiff.Open(fileName, "r");


            FieldValue[] value = input.GetField(TiffTag.IMAGEWIDTH);
            int width = value[0].ToInt();

            value = input.GetField(TiffTag.IMAGELENGTH);
            int height = value[0].ToInt();

            mySize sizeRtn = new mySize(height, width);

            return sizeRtn;
        }

        // 根据偏移指针 大矩阵 和 小矩阵的大小值
        // 得到小矩阵的值
        public static byte[,] GetSmallM(Location handlePoint, byte[,] bCsharp, mySize size)
        {
            byte[,] bSmall = new byte[size.ROW, size.COL];

            int nRow = size.ROW;
            int nCol = size.COL;

            for (int i = 0; i < nRow; i++)
            {
                for (int j = 0; j < nCol; j++)
                {
                    // 
                    // 找寻位置

                    int nRowOff = handlePoint.row;
                    int nColOff = handlePoint.column;
                    int nFindRow = i + nRowOff;
                    int nFindCol = j + nColOff;

                    bSmall[i, j] = bCsharp[nFindRow, nFindCol];
                }
            }

            return bSmall;
        }

        // Write data to file.
        private static void WriteFile(  
                                        int[,] data,
                                        string strFileName
                                        )
        {
            //实例化一个文件流--->与写入文件相关联
            FileStream fs = new FileStream(strFileName, FileMode.Create);
            //实例化一个StreamWriter-->与fs相关联
            StreamWriter sw = new StreamWriter(fs);

            // 开始写入二维数组，按照某种格式

            /*
            foreach (DCoordinate each in listOut)
            {
                sw.WriteLine(each.Y);
            } 
            */


            int iRow = data.GetLength(0);       // 行数
            int iColumn = data.GetLength(1);    // 列数

            for (int i = 0; i < iRow; i++)
            {
                for (int j = 0; j < iColumn; j++)
                {
                    // 先输出数字，在输出逗号.
                    // 如果为最后一个数字，则输出换行

                    if (j == (iColumn - 1))
                    {
                        sw.Write(data[i, j]);
                        sw.WriteLine();
                    }
                    else 
                    {
                        sw.Write(data[i, j]); 
                        sw.Write(",");     
                    }

                }
            }


                //清空缓冲区
                sw.Flush();
            //关闭流
            sw.Close();
            fs.Close();
        }

        // Write data to file.
        private static void WriteFile(
                                        double[,] data,
                                        string strFileName
                                        )
        {
            //实例化一个文件流--->与写入文件相关联
            FileStream fs = new FileStream(strFileName, FileMode.Create);
            //实例化一个StreamWriter-->与fs相关联
            StreamWriter sw = new StreamWriter(fs);

            // 开始写入二维数组，按照某种格式
            int iRow = data.GetLength(0);       // 行数
            int iColumn = data.GetLength(1);    // 列数

            for (int i = 0; i < iRow; i++)
            {
                for (int j = 0; j < iColumn; j++)
                {
                    // 先输出数字，在输出逗号.
                    // 如果为最后一个数字，则输出换行

                    if (j == (iColumn - 1))
                    {
                        sw.Write(data[i, j]);
                        sw.WriteLine();
                    }
                    else
                    {
                        sw.Write(data[i, j]);
                        sw.Write(",");
                    }

                }
            }


            //清空缓冲区
            sw.Flush();
            //关闭流
            sw.Close();
            fs.Close();
        }

        // 把Uint8转换为double类型
        private static double[,] ChangetoDouble(int[,] data)
        {


            int iRow = data.GetLength(0);       // 行数
            int iColumn = data.GetLength(1);    // 列数

            double[,] doubleRtn = new double[iRow, iColumn];

            for (int i = 0; i < iRow; i++)
            {
                for (int j = 0; j < iColumn; j++)
                {
                    double dTemp = 0.0;
                    double Uint8 = 255.0;

                    dTemp = data[i, j] / Uint8;
                    doubleRtn[i, j] = Math.Round(dTemp, 5);
                }
            }

            return doubleRtn;
        }

        // 根据左上角坐标来改变相应的像素值颜色.
        // 注意是偏移量百分比
        public static void DrawRetangle(    
                                        byte[,] Basepic, 
                                        double[,] MatchPic,
                                        Location bestLocation, 
                                        Matrix MatrixG)
        {
            // 用bestLocation和MatrixG 算出偏移百分比
            // 用小图和大图算出 这个小图在这个大图里可以偏移的总量
            // 偏移总量 * 偏移百分比 = 需要标注的坐标点
            // 从这个点画一个小图大小的白框

            // Basepic : 大图矩阵
            // MatchPic: 小图矩阵
            // bestLocation: MatrixG中的最大值坐标点
            // MatrixG： 匹配矩阵


            // (0,0)点代表有8格的误差,
            // 从(4,4)点开始，作为内圈向外扩展
            // 算出偏移百分比 比如在26 26 中的位置 就是一个值
            // 这个值 / 26 获得偏移百分比值
            // 然后在200*200 与 400*400 的关系里， 带入这个偏移百分比值, 获得偏移像素值
            // 由左上角点 + 偏移像素值  就可以做出图形
            // 如果返回起始位置，则认为偏移量是1%



            double dOffRow;
            double dOffCol;
            // 偏移百分比，如果是0， 则返回0.01.
            if (0 == bestLocation.row)
            {
                dOffRow = 0.01;
            }
            else {
                dOffRow = Convert.ToDouble(bestLocation.row) / MatrixG.Row;
            }

            if (0 == bestLocation.column)
            {
                dOffCol = 0.01;
            }
            else {
                dOffCol = Convert.ToDouble(bestLocation.column) / MatrixG.Column;
            }
            

            // 算出偏移总量
            int nOffRowSum = BasePicHandle.GetROW(Basepic) - BasePicHandle.GetROW(MatchPic);
            int nOffColSum = BasePicHandle.GetCOL(Basepic) - BasePicHandle.GetCOL(MatchPic);


            // 算出需要标注的坐标点  =  偏移总量 * 偏移百分比

            int nLRow = Convert.ToInt32( Math.Floor(dOffRow * nOffRowSum) );
            int nLCol = Convert.ToInt32( Math.Floor(dOffCol * nOffColSum) );

            // 从这个点画一个小图大小的白框(灰度时 值为255) 在大图Basepic上面画小图
            int nSizeDrawRow = BasePicHandle.GetROW(MatchPic);
            int nSizeDrawCol = BasePicHandle.GetCOL(MatchPic);

            
            // 偏移指针 基准点的值
            int OFFRow = nLRow;
            int OFFCol = nLCol;

            // 上 Row不变 Col改变大小
            for (int i = 0; i < nSizeDrawCol; i++)
            {
                int nCurCol = OFFCol + i;
                int nCurRow = OFFRow;
                Basepic[nCurRow, nCurCol] = 255;
            }


            // 下 Row + RowSize - 1 为坐标点, Col改变大小
            for (int i = 0; i < nSizeDrawCol; i++)
            {
                int nCurCol = OFFCol + i;
                int nCurRow = OFFRow + nSizeDrawRow - 1;
                Basepic[nCurRow, nCurCol] = 255;
            }


            // 左 Col不变， Row改变大小 为基准点
            for (int i = 0; i < nSizeDrawRow; i++)
            {
                int nCurCol = OFFCol;
                int nCurRow = OFFRow + i;
                Basepic[nCurRow, nCurCol] = 255;
            }

            // 右 Col + ColSize - 1， Row改变大小 
            for (int i = 0; i < nSizeDrawRow; i++)
            {
                int nCurCol = OFFCol + nSizeDrawCol - 1;
                int nCurRow = OFFRow + i;
                Basepic[nCurRow, nCurCol] = 255;
            }

        }

        /// <summary>
        /// 对图片的准确位置进行换算
        /// </summary>
        /// <param name="Basepic"></param>
        /// <param name="MatchPic"></param>
        /// <param name="bestLocation"></param>
        /// <param name="MatrixG"></param>
        /// <returns></returns>
        public static Location GetLocation(byte[,] Basepic, 
                                            double[,] MatchPic, 
                                            Location bestLocation, 
                                            Matrix MatrixG)
        {
            Location lRtn = new Location(0, 0);

            // 用bestLocation和MatrixG 算出偏移百分比
            // 用小图和大图算出 这个小图在这个大图里可以偏移的总量
            // 偏移总量 * 偏移百分比 = 需要标注的坐标点
            // 从这个点画一个小图大小的白框

            // Basepic : 大图矩阵
            // MatchPic: 小图矩阵
            // bestLocation: MatrixG中的最大值坐标点
            // MatrixG： 匹配矩阵


            // (0,0)点代表有8格的误差,
            // 从(4,4)点开始，作为内圈向外扩展
            // 算出偏移百分比 比如在26 26 中的位置 就是一个值
            // 这个值 / 26 获得偏移百分比值
            // 然后在200*200 与 400*400 的关系里， 带入这个偏移百分比值, 获得偏移像素值
            // 由左上角点 + 偏移像素值  就可以做出图形
            // 如果返回起始位置，则认为偏移量是1%



            double dOffRow;
            double dOffCol;
            // 偏移百分比，如果是0， 则返回0.01.
            if (0 == bestLocation.row)
            {
                dOffRow = 0.01;
            }
            else
            {
                dOffRow = Convert.ToDouble(bestLocation.row) / MatrixG.Row;
            }

            if (0 == bestLocation.column)
            {
                dOffCol = 0.01;
            }
            else
            {
                dOffCol = Convert.ToDouble(bestLocation.column) / MatrixG.Column;
            }


            // 算出偏移总量
            int nOffRowSum = BasePicHandle.GetROW(Basepic) - BasePicHandle.GetROW(MatchPic);
            int nOffColSum = BasePicHandle.GetCOL(Basepic) - BasePicHandle.GetCOL(MatchPic);


            // 算出需要标注的坐标点  =  偏移总量 * 偏移百分比

            int nLRow = Convert.ToInt32(Math.Floor(dOffRow * nOffRowSum));
            int nLCol = Convert.ToInt32(Math.Floor(dOffCol * nOffColSum));

            lRtn.row = nLRow;
            lRtn.column = nLCol;

            return lRtn;
        }


        public static void DrawRetangle(byte[,] Basepic, byte[,] MatchPic, Location getLocation)
        {
            // 从这个点画一个小图大小的白框(灰度时 值为255) 在大图Basepic上面画小图
            int nSizeDrawRow = BasePicHandle.GetROW(MatchPic);
            int nSizeDrawCol = BasePicHandle.GetCOL(MatchPic);


            // 偏移指针 基准点的值
            int OFFRow = getLocation.row;
            int OFFCol = getLocation.column;

            // 上 Row不变 Col改变大小
            for (int i = 0; i < nSizeDrawCol; i++)
            {
                int nCurCol = OFFCol + i;
                int nCurRow = OFFRow;
                Basepic[nCurRow, nCurCol] = 255;
            }


            // 下 Row + RowSize - 1 为坐标点, Col改变大小
            for (int i = 0; i < nSizeDrawCol; i++)
            {
                int nCurCol = OFFCol + i;
                int nCurRow = OFFRow + nSizeDrawRow - 1;
                Basepic[nCurRow, nCurCol] = 255;
            }


            // 左 Col不变， Row改变大小 为基准点
            for (int i = 0; i < nSizeDrawRow; i++)
            {
                int nCurCol = OFFCol;
                int nCurRow = OFFRow + i;
                Basepic[nCurRow, nCurCol] = 255;
            }

            // 右 Col + ColSize - 1， Row改变大小 
            for (int i = 0; i < nSizeDrawRow; i++)
            {
                int nCurCol = OFFCol + nSizeDrawCol - 1;
                int nCurRow = OFFRow + i;
                Basepic[nCurRow, nCurCol] = 255;
            }
        }
    }
}
